package com.hp.bon.logreverse;

import com.hp.bon.logreverse.bi.BICallParam;
import com.hp.bon.logreverse.buzBeans.BuzConfig;
import com.hp.bon.logreverse.buzBeans.BuzReadLog;
import com.hp.bon.sgw.bean.XmlMessage;
import com.hp.bon.sgw.util.Comutils;
import com.hp.ocs.diameter.message.Message;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.Element;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Transactional;

public class ExtractBuzInfoService
{
  private static final Logger logger = LoggerFactory.getLogger(ExtractBuzInfoService.class);
  private SessionFactory sessionFactory;
  private Map<String, List<BuzConfig>> BuzConfigMap = null;

  @Transactional
  public List<String> extractMsg(BICallParam param) {
    List ret = null;
    try
    {
      List<BuzConfig> listCfg = null;
      String capability = param.getServiceContextId().substring(0, param.getServiceContextId().indexOf('@'));
      listCfg = (List<BuzConfig>)getBuzConfigMap().get(capability);

      if (listCfg == null) {
        return null;
      }

      if (listCfg == null) return null;
      String tableName = ((BuzConfig)listCfg.get(0)).getTableName().toUpperCase();
      StringBuilder sb = new StringBuilder();
      StringBuilder sb_value = new StringBuilder();

      sb.append("A01_FILE_NM,A02_DB_TIME,A03_LINE_NUM, A04_REQUEST_HOST,A05_SESSION_ID, A06_SERVICE_CONTEXT_ID, A07_MSG_TIME");
      String requestTime = Comutils.formatTime(param.getRequestTime(), "yyyyMMddHHmmss.SSS");
      String tableYYYYMM = Comutils.formatTime(param.getRequestTime(), "yyyyMM");
      sb_value.append("'" + param.getFileName() + "',sysdate," + param.getLineNum() + ",'" + param.getNodeName() + "','" + param.getSessionId() + "','" + param.getServiceContextId() + "','" + requestTime + "'");
      String value = null;
      if (param.getProtocol() == 0) {
        for (BuzConfig bc : listCfg) {
          if ("R".equals(bc.getMsgType())) {
            value = ExtractHelper.getAvpValue((Message)param.getRequest(), bc.getAvpPath(), bc.getAvpType());
          }
          else if (param.getAnswer() != null) {
            value = ExtractHelper.getAvpValue((Message)param.getAnswer(), bc.getAvpPath(), bc.getAvpType());
          }

          if (value != null) {
            sb.append(",").append(bc.getColumnName());
            sb_value.append(",'").append(value).append("'");
          }
        }
      } else if (param.getProtocol() == 1) {
        Element elementREQ = null;
        Element elementACK = null;
        XmlMessage answer;
        try { XmlMessage request = (XmlMessage)param.getRequest();
          if (request.getDATA() != null) {
            Document doc = Comutils.parseText(request.getDATA());
            elementREQ = doc.getRootElement();
          }
          answer = null;
          if (param.getAnswer() != null) {
            answer = (XmlMessage)param.getAnswer();
            if (answer.getDATA() != null) {
              Document doc = Comutils.parseText(answer.getDATA());
              elementACK = doc.getRootElement();
            }
          }
        } catch (Exception e) {
          logger.warn("[" + param.getFileName() + "] extract message failed:" + param.getSessionId());
          return null;
        }

        for (BuzConfig bc : listCfg) {
          if (("R".equals(bc.getMsgType())) && (elementREQ != null))
            value = ExtractHelper.getXmlNodeValue(elementREQ, bc.getXmlPath());
          else if (("A".equals(bc.getMsgType())) && (elementACK != null)) {
            value = ExtractHelper.getXmlNodeValue(elementACK, bc.getXmlPath());
          }
          if (value != null) {
            sb.append(",").append(bc.getColumnName());
            sb_value.append(",'").append(value).append("'");
          }
        }
      }
      ret = new ArrayList();
      String tableNameYYYYMM = ExtractHelper.getTableName(tableName, tableYYYYMM);
      String sql = "insert into " + tableNameYYYYMM + " (" + sb.toString() + ") values (" + sb_value.toString() + " )";
      ret.add(tableNameYYYYMM);
      ret.add(sql);
    }
    catch (Exception e)
    {
      if (param != null)
        logger.warn("Found an illeague format message." + param.toString() + "." + e.getMessage(), e);
      else
        logger.warn("Found an illeague format message,totally couldn't decode!" + e.getMessage(), e);
      ret = null;
    }
    return ret;
  }

  @Transactional
  public void saveDB(BuzReadLog log, List<String> datalist) {
    log.setDbTotalNum(datalist.size());
    int failedNum = flushData(datalist);
    log.setDbFailedNum(failedNum);
    addLog(log);
  }

  @Transactional
  public void createDB(Set<String> tables)
  {
    String sql = "select t.TNAME from TAB t where t.TNAME like 'BUZ_%' and t.TABTYPE='TABLE' order by t.TNAME";
    SQLQuery query = this.sessionFactory.getCurrentSession().createSQLQuery(sql);
    List<String> queryList = query.list();
    if (queryList.isEmpty()) {
      logger.error("Cann't get data from sys.tab,sys.tab$,sys.obj$ ! Please authrize current DB user.");
      System.exit(-1);
    } else {
      Set existTab = new HashSet();
      for (String table : queryList)
      {
        existTab.add(table);
      }
      for (String mustExist : tables)
      {
        if (!existTab.contains(mustExist))
        {
          String originalTableName = mustExist.substring(0, mustExist.lastIndexOf("_"));
          sql = "create table " + mustExist + " as (select * from " + originalTableName + " where 1=2)";
          logger.info("Create table SQL:" + sql);
          this.sessionFactory.getCurrentSession().createSQLQuery(sql).executeUpdate();
          logger.info("Create table " + mustExist);
        }
      }
    }
  }

  @Transactional
  public int flushData(List<String> datalist)
  {
    long start = System.currentTimeMillis();
    org.hibernate.Session session = null;
    Transaction tx = null;
    int failedNum = 0;
    try {
      session = this.sessionFactory.openSession();
      tx = session.beginTransaction();
      Queue queue = new LinkedList();
      for (int i = 0; i < datalist.size(); i++) {
        queue.offer((String)datalist.get(i));
        if (i % 1000 == 0) {
          doSaveData(failedNum, session, tx, queue);
          session.flush();
          session.clear();
        }
      }
      doSaveData(failedNum, session, tx, queue);
      tx.commit();
      logger.info("total " + datalist.size() + " records," + "save failed:" + failedNum + ", ms=" + (System.currentTimeMillis() - start));
    } catch (Exception e) {
      e.fillInStackTrace();
    } finally {
      if (session != null) {
        session.close();
      }
    }
    return failedNum;
  }

  @Transactional
  public void doSaveData(int failedNum, org.hibernate.Session session, Transaction tx, Queue<String> dataSqlQueue) {
    String sqlStr = null;
    try {
      while ((sqlStr = (String)dataSqlQueue.poll()) != null)
        session.createSQLQuery(sqlStr).executeUpdate();
    }
    catch (Exception e) {
      failedNum++;
      logger.warn("FAILED SQL:" + sqlStr);
      if (!dataSqlQueue.isEmpty())
        doSaveData(failedNum, session, tx, dataSqlQueue);
    }
  }

  @Transactional
  public boolean isDupFile(String fileName)
  {
    BuzReadLog lf = (BuzReadLog)this.sessionFactory.getCurrentSession().get(BuzReadLog.class, fileName);
    if (lf == null) {
      return false;
    }
    return true;
  }

  @Transactional
  public void addLog(BuzReadLog lf) {
    this.sessionFactory.getCurrentSession().save(lf);
  }

  @Transactional
  public void updateLog(BuzReadLog lf) {
    this.sessionFactory.getCurrentSession().update(lf);
  }

  @Transactional
  public BuzReadLog getLastFile() {
    String hql = "select f from BuzReadLog f order by f.dbTime desc";
    Query query = this.sessionFactory.getCurrentSession().createQuery(hql);
    if (query.list().isEmpty()) {
      return null;
    }
    return (BuzReadLog)query.list().get(0);
  }

  @Transactional
  public Map<String, List<BuzConfig>> loadBuzConfigMap()
  {
    String hql = "select b from BuzConfig b ";
    Query query = this.sessionFactory.getCurrentSession().createQuery(hql);
    List<BuzConfig> list = query.list();

    Map map = new HashMap();
    List tmp = null;
    for (BuzConfig bc : list) {
      tmp = (List)map.get(bc.getCapability());
      if (tmp == null) {
        tmp = new ArrayList();
        map.put(bc.getCapability(), tmp);
      }
      tmp.add(bc);
    }
    return map;
  }
  @Autowired
  @Qualifier("sessionFactory")
  public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
  }

  @Transactional
  public Map<String, List<BuzConfig>> getBuzConfigMap() {
    if (this.BuzConfigMap == null) {
      this.BuzConfigMap = loadBuzConfigMap();
    }
    return this.BuzConfigMap;
  }
}